Todo:

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ----------------------------------------------------------------------------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.2     v purrr   0.3.4
v tibble  3.1.0     v dplyr   1.0.2
v tidyr   1.1.2     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.0
package 㤼㸱tibble㤼㸲 was built under R version 4.0.4-- Conflicts -------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(readxl)
library(plotly)
package 㤼㸱plotly㤼㸲 was built under R version 4.0.5
Attaching package: 㤼㸱plotly㤼㸲

The following object is masked from 㤼㸱package:ggplot2㤼㸲:

    last_plot

The following object is masked from 㤼㸱package:stats㤼㸲:

    filter

The following object is masked from 㤼㸱package:graphics㤼㸲:

    layout
ghg_emissions_clean <- ghg_emissions_data %>% 
  janitor::clean_names() %>% 
  mutate(units = "megatonnes of co2 equivelant") %>% 
  rename(emissions = emissions_mt_co2e) %>% 
  filter(emission_year != "BaseYear") %>% 
  mutate(emission_year = as.numeric(emission_year)) %>% 
  select(ccp_mapping, source_name, pollutant, year = emission_year, value = 
           emissions, units)
ghg_emissions_clean %>% 
  write_csv("data/clean_data/ghg_emissions.csv")
plotly::ggplotly(
  ghg_emissions_clean %>% 
    filter(year == 2018) %>%
    filter(pollutant %in% c("CO2", "CH4")) %>%
    ggplot() +
    aes(x = factor(ccp_mapping, levels = rev(levels(factor(ccp_mapping)))),
        y = value, fill = source_name,
        text = paste0('</br> Sector: ', ccp_mapping,
                      '</br> Emissions: ', value,
                      '</br> Source Name: ', source_name)) +
    geom_col(position = "stack") +
    theme_bw() +
    theme(legend.position = "none") +
    labs(x = "Sector",
         y = paste0("Emissions (", ghg_emissions_clean$units[1], ")")) +
    coord_flip(),
    tooltip = 'text'
  )
NA
ghg_emissions_data %>% 
  names()
[1] "National Communication Categories" "SG Source Sector"                  "CCP mapping"                       "IPCC"                             
[5] "SourceName"                        "Pollutant"                         "EmissionYear"                      "Emissions (MtCO2e)"               
ghg_emissions_data %>% 
  select()
input <- list()

input$col_choice = "national_communication_categories"
ghg_emissions_clean %>%
  group_by_(input$col_choice, "emission_year") %>% 
  summarise(total_ghg_emissions = sum(emissions))
`summarise()` regrouping output by 'national_communication_categories' (override with `.groups` argument)
ghg_emissions_data %>% 
  distinct(`National Communication Categories`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5)) +
  ylim(0, 80) +
  theme(legend.position = 0) +
  theme_bw()
`summarise()` ungrouping output (override with `.groups` argument)

ghg_emissions_data %>% 
  distinct(`CCP mapping`)
ghg_emissions_data %>% 
  distinct(`National Communication Categories`)
ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  group_by(`CCP mapping`, EmissionYear) %>% 
  summarise(total_ghg_emissions = sum(`Emissions (MtCO2e)`)) %>% 
  ggplot() +
  aes(x = EmissionYear, y = total_ghg_emissions, group = `CCP mapping`, colour = `CCP mapping`) +
  geom_line() +
  geom_point() +
  scale_x_continuous(breaks = seq(1990,2020,5))
`summarise()` regrouping output by 'CCP mapping' (override with `.groups` argument)

ghg_emissions_data %>% 
  filter(EmissionYear != "BaseYear") %>% 
  mutate(EmissionYear = as.numeric(EmissionYear)) %>% 
  filter(`National Communication Categories` != `CCP mapping`) %>% 
  select(`National Communication Categories`, `CCP mapping`) %>% 
  unique()

category_id,category_name,subcategory_id,subcategory_name,year,emissions,emission

emissions_sankey <- emissions_data %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units)
filtered_df <- ghg_emissions_clean %>% 
  select(ccp_mapping, source_name, pollutant, emission_year, emissions, units) %>% 
  filter(pollutant == "CO2") %>% 
  filter(emission_year == "2005")
total_emissions_for_gas <- filtered_df %>% 
  summarise(sum(emissions)) %>% 
  pull()

total_emissions_by_category <- filtered_df %>% 
  select(-pollutant) %>% 
  group_by(ccp_mapping) %>% 
  summarise(cat_sum = sum(emissions), .groups = 'drop_last')
categories <- filtered_df %>% 
  distinct(ccp_mapping) %>% 
  pull()

n_categories <- length(categories)

sources <- filtered_df %>% 
  distinct(source_name) %>% 
  pull()

n_sources <- length(sources)
n_sources
[1] 159
node_names <- c("Total", categories, sources, "Other")

node_names_df <- data.frame("name" = node_names)

total_sankey_tibble <- total_emissions_by_category %>%
  mutate(total = "Total") %>% 
  mutate(total = match(total, node_names) -1) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1) %>% 
  select(source = total,
         target = ccp_mapping,
         value = cat_sum)

total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)


sub_sankey_tibble <- filtered_df %>% 
  select(- c(units, pollutant, emission_year)) %>% 
  mutate(ccp_mapping = match(ccp_mapping, node_names) -1,
         source_name = match(source_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
total_filtered_emissions <- total_sankey_tibble %>% 
  summarise(sum(value)) %>% 
  pull()

other_emissions <- total_emissions_for_gas - total_filtered_emissions

total_other_sankey_tibble <- tibble(
  "source" = c(0),
  "target" = (match("Other", node_names) -1),
  "value" = c(other_emissions)
)

sub_sankey_tibble <- filtered_tibble %>% 
  select(-category_id, -subcategory_id, -year) %>% 
  mutate(category_name = match(category_name, node_names) -1,
         subcategory_name = match(subcategory_name, node_names) -1)

names(sub_sankey_tibble) = c("source", "target", "value")

sankey_tibble <- total_sankey_tibble %>% 
  bind_rows(sub_sankey_tibble) %>% 
  bind_rows(total_other_sankey_tibble)

links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))

# Add a 'group' column to each connection:
links <- links_matrix %>% 
  mutate(group = case_when(
    source == 0 ~ paste("type_", target, sep = ""),
    source!=0 ~ paste("type_", source, sep = "")
  ))

nodes <- node_names_df
# Add a 'group' column to each node.
# All of them in the same group to make them the same colour
nodes$group <- as.factor(c("my_unique_group"))

emissions <- list()

emissions$nodes <- nodes
emissions$links <- links
make_sankey_dfs <- function(data, userYear, userGas) {
  n_categories <- data %>% 
    distinct(category_name) %>% 
    nrow()
  
  total_emissions_for_gas <- data %>% 
    filter(emission == userGas()) %>% 
    filter(year == userYear()) %>%
    summarise(sum(emissions)) %>% 
    pull()
  
  filtered_tibble <- data %>%
    filter(emission == userGas()) %>% 
    select(-emission) %>% 
    filter(year == userYear()) %>% 
    filter(emissions > userResolution())
  
  total_emissions_by_cat <- filtered_tibble %>%
    group_by(category_name) %>% 
    summarise(cat_sum = sum(emissions), .groups = 'drop_last')
  
  categories <- filtered_tibble %>%
    distinct(category_name) %>% 
    pull()
  
  subcategories <- filtered_tibble %>%
    distinct(subcategory_name) %>% 
    pull()
  
  node_names <- c("Total", categories, subcategories, "Other")
  
  node_names_df <- data.frame("name" = node_names)
  
  total_sankey_tibble <- total_emissions_by_cat %>%
    mutate(total = "Total") %>% 
    mutate(total = match(total, node_names) -1) %>% 
    mutate(category_name = match(category_name, node_names) -1) %>% 
    select(source = total,
           target = category_name,
           value = cat_sum)
  
  total_filtered_emissions <- total_sankey_tibble %>% 
    summarise(sum(value)) %>% 
    pull()
  
  other_emissions <- total_emissions_for_gas - total_filtered_emissions
  
  total_other_sankey_tibble <- tibble(
    "source" = c(0),
    "target" = (match("Other", node_names) -1),
    "value" = c(other_emissions)
  )
  
  sub_sankey_tibble <- filtered_tibble %>% 
    select(-category_id, -subcategory_id, -year) %>% 
    mutate(category_name = match(category_name, node_names) -1,
           subcategory_name = match(subcategory_name, node_names) -1)
  
  names(sub_sankey_tibble) = c("source", "target", "value")
  
  sankey_tibble <- total_sankey_tibble %>% 
    bind_rows(sub_sankey_tibble) %>% 
    bind_rows(total_other_sankey_tibble)
  
  links_matrix <- data.frame(as.matrix(sankey_tibble, byrow = TRUE, ncols = 3))
  
  # Add a 'group' column to each connection:
  links <- links_matrix %>% 
    mutate(group = case_when(
      source == 0 ~ paste("type_", target, sep = ""),
      source!=0 ~ paste("type_", source, sep = "")
    ))
  
  nodes <- node_names_df
  # Add a 'group' column to each node.
  # All of them in the same group to make them the same colour
  nodes$group <- as.factor(c("my_unique_group"))
  
  emissions <- list()
  
  emissions$nodes <- nodes
  emissions$links <- links
  
  return(emissions)
}
make_sankey_dfs(emissions_sankey, userYear = 2005, userGas = "CH4", userResolution = 50)
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyBUb2RvOg0KDQotIGFkZCBjb2x1bW5zIGZvciB0b3RhbHMgZm9yIGVhY2ggcG9sbHV0YW50L3NlY3Rvcg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHBsb3RseSkNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSA8LSByZWFkX3hsc3goImRhdGEvcmF3X2RhdGEvc2NvdHRpc2gtZ2hnLWRhdGFzZXQtMjAxOC54bHN4IiwgMikNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfY2xlYW4gPC0gZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgDQogIG11dGF0ZSh1bml0cyA9ICJtZWdhdG9ubmVzIG9mIGNvMiBlcXVpdmVsYW50IikgJT4lIA0KICByZW5hbWUoZW1pc3Npb25zID0gZW1pc3Npb25zX210X2NvMmUpICU+JSANCiAgZmlsdGVyKGVtaXNzaW9uX3llYXIgIT0gIkJhc2VZZWFyIikgJT4lIA0KICBtdXRhdGUoZW1pc3Npb25feWVhciA9IGFzLm51bWVyaWMoZW1pc3Npb25feWVhcikpICU+JSANCiAgc2VsZWN0KGNjcF9tYXBwaW5nLCBzb3VyY2VfbmFtZSwgcG9sbHV0YW50LCB5ZWFyID0gZW1pc3Npb25feWVhciwgdmFsdWUgPSANCiAgICAgICAgICAgZW1pc3Npb25zLCB1bml0cykNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICB3cml0ZV9jc3YoImRhdGEvY2xlYW5fZGF0YS9naGdfZW1pc3Npb25zLmNzdiIpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3RseTo6Z2dwbG90bHkoDQogIGdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IDIwMTgpICU+JQ0KICAgIGZpbHRlcihwb2xsdXRhbnQgJWluJSBjKCJDTzIiLCAiQ0g0IikpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoeCA9IGZhY3RvcihjY3BfbWFwcGluZywgbGV2ZWxzID0gcmV2KGxldmVscyhmYWN0b3IoY2NwX21hcHBpbmcpKSkpLA0KICAgICAgICB5ID0gdmFsdWUsIGZpbGwgPSBzb3VyY2VfbmFtZSwNCiAgICAgICAgdGV4dCA9IHBhc3RlMCgnPC9icj4gU2VjdG9yOiAnLCBjY3BfbWFwcGluZywNCiAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gRW1pc3Npb25zOiAnLCB2YWx1ZSwNCiAgICAgICAgICAgICAgICAgICAgICAnPC9icj4gU291cmNlIE5hbWU6ICcsIHNvdXJjZV9uYW1lKSkgKw0KICAgIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIikgKw0KICAgIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICAgIGxhYnMoeCA9ICJTZWN0b3IiLA0KICAgICAgICAgeSA9IHBhc3RlMCgiRW1pc3Npb25zICgiLCBnaGdfZW1pc3Npb25zX2NsZWFuJHVuaXRzWzFdLCAiKSIpKSArDQogICAgY29vcmRfZmxpcCgpLA0KICAgIHRvb2x0aXAgPSAndGV4dCcNCiAgKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIG5hbWVzKCkNCmBgYA0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIHNlbGVjdCgpDQpgYGANCg0KDQoNCmBgYHtyfQ0KaW5wdXQgPC0gbGlzdCgpDQoNCmlucHV0JGNvbF9jaG9pY2UgPSAibmF0aW9uYWxfY29tbXVuaWNhdGlvbl9jYXRlZ29yaWVzIg0KYGBgDQoNCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfY2xlYW4gJT4lDQogIGdyb3VwX2J5XyhpbnB1dCRjb2xfY2hvaWNlLCAiZW1pc3Npb25feWVhciIpICU+JSANCiAgc3VtbWFyaXNlKHRvdGFsX2doZ19lbWlzc2lvbnMgPSBzdW0oZW1pc3Npb25zKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucywgZ3JvdXAgPSBgTmF0aW9uYWwgQ29tbXVuaWNhdGlvbiBDYXRlZ29yaWVzYCwgY29sb3VyID0gYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDE5OTAsMjAyMCw1KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAwKQ0KYGBgDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZGlzdGluY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZmlsdGVyKEVtaXNzaW9uWWVhciAhPSAiQmFzZVllYXIiKSAlPiUgDQogIG11dGF0ZShFbWlzc2lvblllYXIgPSBhcy5udW1lcmljKEVtaXNzaW9uWWVhcikpICU+JSANCiAgZ3JvdXBfYnkoRW1pc3Npb25ZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9naGdfZW1pc3Npb25zID0gc3VtKGBFbWlzc2lvbnMgKE10Q08yZSlgKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucykgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk5MCwyMDIwLDUpKSArDQogIHlsaW0oMCwgODApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gMCkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KDQpgYGB7cn0NCmdoZ19lbWlzc2lvbnNfZGF0YSAlPiUgDQogIGRpc3RpbmN0KGBDQ1AgbWFwcGluZ2ApDQpgYGANCg0KYGBge3J9DQoNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZGlzdGluY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2ApDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhDQpgYGANCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19kYXRhICU+JSANCiAgZmlsdGVyKEVtaXNzaW9uWWVhciAhPSAiQmFzZVllYXIiKSAlPiUgDQogIG11dGF0ZShFbWlzc2lvblllYXIgPSBhcy5udW1lcmljKEVtaXNzaW9uWWVhcikpICU+JSANCiAgZ3JvdXBfYnkoYENDUCBtYXBwaW5nYCwgRW1pc3Npb25ZZWFyKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbF9naGdfZW1pc3Npb25zID0gc3VtKGBFbWlzc2lvbnMgKE10Q08yZSlgKSkgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGFlcyh4ID0gRW1pc3Npb25ZZWFyLCB5ID0gdG90YWxfZ2hnX2VtaXNzaW9ucywgZ3JvdXAgPSBgQ0NQIG1hcHBpbmdgLCBjb2xvdXIgPSBgQ0NQIG1hcHBpbmdgKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTkwLDIwMjAsNSkpDQpgYGANCg0KYGBge3J9DQpnaGdfZW1pc3Npb25zX2RhdGEgJT4lIA0KICBmaWx0ZXIoRW1pc3Npb25ZZWFyICE9ICJCYXNlWWVhciIpICU+JSANCiAgbXV0YXRlKEVtaXNzaW9uWWVhciA9IGFzLm51bWVyaWMoRW1pc3Npb25ZZWFyKSkgJT4lIA0KICBmaWx0ZXIoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2AgIT0gYENDUCBtYXBwaW5nYCkgJT4lIA0KICBzZWxlY3QoYE5hdGlvbmFsIENvbW11bmljYXRpb24gQ2F0ZWdvcmllc2AsIGBDQ1AgbWFwcGluZ2ApICU+JSANCiAgdW5pcXVlKCkNCmBgYA0KY2F0ZWdvcnlfaWQsY2F0ZWdvcnlfbmFtZSxzdWJjYXRlZ29yeV9pZCxzdWJjYXRlZ29yeV9uYW1lLHllYXIsZW1pc3Npb25zLGVtaXNzaW9uDQoNCmBgYHtyfQ0KZW1pc3Npb25zX3NhbmtleSA8LSBlbWlzc2lvbnNfZGF0YSAlPiUgDQogIHNlbGVjdChjY3BfbWFwcGluZywgc291cmNlX25hbWUsIHBvbGx1dGFudCwgZW1pc3Npb25feWVhciwgZW1pc3Npb25zLCB1bml0cykNCmBgYA0KDQoNCmBgYHtyfQ0KZ2hnX2VtaXNzaW9uc19jbGVhbg0KYGBgDQoNCg0KYGBge3J9DQpmaWx0ZXJlZF9kZiA8LSBnaGdfZW1pc3Npb25zX2NsZWFuICU+JSANCiAgc2VsZWN0KGNjcF9tYXBwaW5nLCBzb3VyY2VfbmFtZSwgcG9sbHV0YW50LCBlbWlzc2lvbl95ZWFyLCBlbWlzc2lvbnMsIHVuaXRzKSAlPiUgDQogIGZpbHRlcihwb2xsdXRhbnQgPT0gIkNPMiIpICU+JSANCiAgZmlsdGVyKGVtaXNzaW9uX3llYXIgPT0gIjIwMDUiKQ0KYGBgDQoNCmBgYHtyfQ0KdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgPC0gZmlsdGVyZWRfZGYgJT4lIA0KICBzdW1tYXJpc2Uoc3VtKGVtaXNzaW9ucykpICU+JSANCiAgcHVsbCgpDQoNCnRvdGFsX2VtaXNzaW9uc19ieV9jYXRlZ29yeSA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIHNlbGVjdCgtcG9sbHV0YW50KSAlPiUgDQogIGdyb3VwX2J5KGNjcF9tYXBwaW5nKSAlPiUgDQogIHN1bW1hcmlzZShjYXRfc3VtID0gc3VtKGVtaXNzaW9ucyksIC5ncm91cHMgPSAnZHJvcF9sYXN0JykNCmBgYA0KDQpgYGB7cn0NCmNhdGVnb3JpZXMgPC0gZmlsdGVyZWRfZGYgJT4lIA0KICBkaXN0aW5jdChjY3BfbWFwcGluZykgJT4lIA0KICBwdWxsKCkNCg0Kbl9jYXRlZ29yaWVzIDwtIGxlbmd0aChjYXRlZ29yaWVzKQ0KDQpzb3VyY2VzIDwtIGZpbHRlcmVkX2RmICU+JSANCiAgZGlzdGluY3Qoc291cmNlX25hbWUpICU+JSANCiAgcHVsbCgpDQoNCm5fc291cmNlcyA8LSBsZW5ndGgoc291cmNlcykNCmBgYA0KDQpgYGB7cn0NCm5fc291cmNlcw0KYGBgDQoNCg0KYGBge3J9DQpub2RlX25hbWVzIDwtIGMoIlRvdGFsIiwgY2F0ZWdvcmllcywgc291cmNlcywgIk90aGVyIikNCg0Kbm9kZV9uYW1lc19kZiA8LSBkYXRhLmZyYW1lKCJuYW1lIiA9IG5vZGVfbmFtZXMpDQoNCnRvdGFsX3NhbmtleV90aWJibGUgPC0gdG90YWxfZW1pc3Npb25zX2J5X2NhdGVnb3J5ICU+JQ0KICBtdXRhdGUodG90YWwgPSAiVG90YWwiKSAlPiUgDQogIG11dGF0ZSh0b3RhbCA9IG1hdGNoKHRvdGFsLCBub2RlX25hbWVzKSAtMSkgJT4lIA0KICBtdXRhdGUoY2NwX21hcHBpbmcgPSBtYXRjaChjY3BfbWFwcGluZywgbm9kZV9uYW1lcykgLTEpICU+JSANCiAgc2VsZWN0KHNvdXJjZSA9IHRvdGFsLA0KICAgICAgICAgdGFyZ2V0ID0gY2NwX21hcHBpbmcsDQogICAgICAgICB2YWx1ZSA9IGNhdF9zdW0pDQoNCnRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucyA8LSB0b3RhbF9zYW5rZXlfdGliYmxlICU+JSANCiAgc3VtbWFyaXNlKHN1bSh2YWx1ZSkpICU+JSANCiAgcHVsbCgpDQoNCm90aGVyX2VtaXNzaW9ucyA8LSB0b3RhbF9lbWlzc2lvbnNfZm9yX2dhcyAtIHRvdGFsX2ZpbHRlcmVkX2VtaXNzaW9ucw0KDQp0b3RhbF9vdGhlcl9zYW5rZXlfdGliYmxlIDwtIHRpYmJsZSgNCiAgInNvdXJjZSIgPSBjKDApLA0KICAidGFyZ2V0IiA9IChtYXRjaCgiT3RoZXIiLCBub2RlX25hbWVzKSAtMSksDQogICJ2YWx1ZSIgPSBjKG90aGVyX2VtaXNzaW9ucykNCikNCg0KDQpzdWJfc2Fua2V5X3RpYmJsZSA8LSBmaWx0ZXJlZF9kZiAlPiUgDQogIHNlbGVjdCgtIGModW5pdHMsIHBvbGx1dGFudCwgZW1pc3Npb25feWVhcikpICU+JSANCiAgbXV0YXRlKGNjcF9tYXBwaW5nID0gbWF0Y2goY2NwX21hcHBpbmcsIG5vZGVfbmFtZXMpIC0xLA0KICAgICAgICAgc291cmNlX25hbWUgPSBtYXRjaChzb3VyY2VfbmFtZSwgbm9kZV9uYW1lcykgLTEpDQoNCm5hbWVzKHN1Yl9zYW5rZXlfdGliYmxlKSA9IGMoInNvdXJjZSIsICJ0YXJnZXQiLCAidmFsdWUiKQ0KDQpzYW5rZXlfdGliYmxlIDwtIHRvdGFsX3NhbmtleV90aWJibGUgJT4lIA0KICBiaW5kX3Jvd3Moc3ViX3NhbmtleV90aWJibGUpICU+JSANCiAgYmluZF9yb3dzKHRvdGFsX290aGVyX3NhbmtleV90aWJibGUpDQoNCmxpbmtzX21hdHJpeCA8LSBkYXRhLmZyYW1lKGFzLm1hdHJpeChzYW5rZXlfdGliYmxlLCBieXJvdyA9IFRSVUUsIG5jb2xzID0gMykpDQoNCiMgQWRkIGEgJ2dyb3VwJyBjb2x1bW4gdG8gZWFjaCBjb25uZWN0aW9uOg0KbGlua3MgPC0gbGlua3NfbWF0cml4ICU+JSANCiAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKA0KICAgIHNvdXJjZSA9PSAwIH4gcGFzdGUoInR5cGVfIiwgdGFyZ2V0LCBzZXAgPSAiIiksDQogICAgc291cmNlIT0wIH4gcGFzdGUoInR5cGVfIiwgc291cmNlLCBzZXAgPSAiIikNCiAgKSkNCg0Kbm9kZXMgPC0gbm9kZV9uYW1lc19kZg0KIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIG5vZGUuDQojIEFsbCBvZiB0aGVtIGluIHRoZSBzYW1lIGdyb3VwIHRvIG1ha2UgdGhlbSB0aGUgc2FtZSBjb2xvdXINCm5vZGVzJGdyb3VwIDwtIGFzLmZhY3RvcihjKCJteV91bmlxdWVfZ3JvdXAiKSkNCg0KZW1pc3Npb25zIDwtIGxpc3QoKQ0KDQplbWlzc2lvbnMkbm9kZXMgPC0gbm9kZXMNCmVtaXNzaW9ucyRsaW5rcyA8LSBsaW5rcw0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KYGBge3J9DQp0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogIHN1bW1hcmlzZShzdW0odmFsdWUpKSAlPiUgDQogIHB1bGwoKQ0KDQpvdGhlcl9lbWlzc2lvbnMgPC0gdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgLSB0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMNCg0KdG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSA8LSB0aWJibGUoDQogICJzb3VyY2UiID0gYygwKSwNCiAgInRhcmdldCIgPSAobWF0Y2goIk90aGVyIiwgbm9kZV9uYW1lcykgLTEpLA0KICAidmFsdWUiID0gYyhvdGhlcl9lbWlzc2lvbnMpDQopDQoNCnN1Yl9zYW5rZXlfdGliYmxlIDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUgDQogIHNlbGVjdCgtY2F0ZWdvcnlfaWQsIC1zdWJjYXRlZ29yeV9pZCwgLXllYXIpICU+JSANCiAgbXV0YXRlKGNhdGVnb3J5X25hbWUgPSBtYXRjaChjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSwNCiAgICAgICAgIHN1YmNhdGVnb3J5X25hbWUgPSBtYXRjaChzdWJjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSkNCg0KbmFtZXMoc3ViX3NhbmtleV90aWJibGUpID0gYygic291cmNlIiwgInRhcmdldCIsICJ2YWx1ZSIpDQoNCnNhbmtleV90aWJibGUgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogIGJpbmRfcm93cyhzdWJfc2Fua2V5X3RpYmJsZSkgJT4lIA0KICBiaW5kX3Jvd3ModG90YWxfb3RoZXJfc2Fua2V5X3RpYmJsZSkNCg0KbGlua3NfbWF0cml4IDwtIGRhdGEuZnJhbWUoYXMubWF0cml4KHNhbmtleV90aWJibGUsIGJ5cm93ID0gVFJVRSwgbmNvbHMgPSAzKSkNCg0KIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIGNvbm5lY3Rpb246DQpsaW5rcyA8LSBsaW5rc19tYXRyaXggJT4lIA0KICBtdXRhdGUoZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgc291cmNlID09IDAgfiBwYXN0ZSgidHlwZV8iLCB0YXJnZXQsIHNlcCA9ICIiKSwNCiAgICBzb3VyY2UhPTAgfiBwYXN0ZSgidHlwZV8iLCBzb3VyY2UsIHNlcCA9ICIiKQ0KICApKQ0KDQpub2RlcyA8LSBub2RlX25hbWVzX2RmDQojIEFkZCBhICdncm91cCcgY29sdW1uIHRvIGVhY2ggbm9kZS4NCiMgQWxsIG9mIHRoZW0gaW4gdGhlIHNhbWUgZ3JvdXAgdG8gbWFrZSB0aGVtIHRoZSBzYW1lIGNvbG91cg0Kbm9kZXMkZ3JvdXAgPC0gYXMuZmFjdG9yKGMoIm15X3VuaXF1ZV9ncm91cCIpKQ0KDQplbWlzc2lvbnMgPC0gbGlzdCgpDQoNCmVtaXNzaW9ucyRub2RlcyA8LSBub2Rlcw0KZW1pc3Npb25zJGxpbmtzIDwtIGxpbmtzDQpgYGANCg0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCm1ha2Vfc2Fua2V5X2RmcyA8LSBmdW5jdGlvbihkYXRhLCB1c2VyWWVhciwgdXNlckdhcykgew0KICBuX2NhdGVnb3JpZXMgPC0gZGF0YSAlPiUgDQogICAgZGlzdGluY3QoY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIG5yb3coKQ0KICANCiAgdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgPC0gZGF0YSAlPiUgDQogICAgZmlsdGVyKGVtaXNzaW9uID09IHVzZXJHYXMoKSkgJT4lIA0KICAgIGZpbHRlcih5ZWFyID09IHVzZXJZZWFyKCkpICU+JQ0KICAgIHN1bW1hcmlzZShzdW0oZW1pc3Npb25zKSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgZmlsdGVyZWRfdGliYmxlIDwtIGRhdGEgJT4lDQogICAgZmlsdGVyKGVtaXNzaW9uID09IHVzZXJHYXMoKSkgJT4lIA0KICAgIHNlbGVjdCgtZW1pc3Npb24pICU+JSANCiAgICBmaWx0ZXIoeWVhciA9PSB1c2VyWWVhcigpKSAlPiUgDQogICAgZmlsdGVyKGVtaXNzaW9ucyA+IHVzZXJSZXNvbHV0aW9uKCkpDQogIA0KICB0b3RhbF9lbWlzc2lvbnNfYnlfY2F0IDwtIGZpbHRlcmVkX3RpYmJsZSAlPiUNCiAgICBncm91cF9ieShjYXRlZ29yeV9uYW1lKSAlPiUgDQogICAgc3VtbWFyaXNlKGNhdF9zdW0gPSBzdW0oZW1pc3Npb25zKSwgLmdyb3VwcyA9ICdkcm9wX2xhc3QnKQ0KICANCiAgY2F0ZWdvcmllcyA8LSBmaWx0ZXJlZF90aWJibGUgJT4lDQogICAgZGlzdGluY3QoY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgc3ViY2F0ZWdvcmllcyA8LSBmaWx0ZXJlZF90aWJibGUgJT4lDQogICAgZGlzdGluY3Qoc3ViY2F0ZWdvcnlfbmFtZSkgJT4lIA0KICAgIHB1bGwoKQ0KICANCiAgbm9kZV9uYW1lcyA8LSBjKCJUb3RhbCIsIGNhdGVnb3JpZXMsIHN1YmNhdGVnb3JpZXMsICJPdGhlciIpDQogIA0KICBub2RlX25hbWVzX2RmIDwtIGRhdGEuZnJhbWUoIm5hbWUiID0gbm9kZV9uYW1lcykNCiAgDQogIHRvdGFsX3NhbmtleV90aWJibGUgPC0gdG90YWxfZW1pc3Npb25zX2J5X2NhdCAlPiUNCiAgICBtdXRhdGUodG90YWwgPSAiVG90YWwiKSAlPiUgDQogICAgbXV0YXRlKHRvdGFsID0gbWF0Y2godG90YWwsIG5vZGVfbmFtZXMpIC0xKSAlPiUgDQogICAgbXV0YXRlKGNhdGVnb3J5X25hbWUgPSBtYXRjaChjYXRlZ29yeV9uYW1lLCBub2RlX25hbWVzKSAtMSkgJT4lIA0KICAgIHNlbGVjdChzb3VyY2UgPSB0b3RhbCwNCiAgICAgICAgICAgdGFyZ2V0ID0gY2F0ZWdvcnlfbmFtZSwNCiAgICAgICAgICAgdmFsdWUgPSBjYXRfc3VtKQ0KICANCiAgdG90YWxfZmlsdGVyZWRfZW1pc3Npb25zIDwtIHRvdGFsX3NhbmtleV90aWJibGUgJT4lIA0KICAgIHN1bW1hcmlzZShzdW0odmFsdWUpKSAlPiUgDQogICAgcHVsbCgpDQogIA0KICBvdGhlcl9lbWlzc2lvbnMgPC0gdG90YWxfZW1pc3Npb25zX2Zvcl9nYXMgLSB0b3RhbF9maWx0ZXJlZF9lbWlzc2lvbnMNCiAgDQogIHRvdGFsX290aGVyX3NhbmtleV90aWJibGUgPC0gdGliYmxlKA0KICAgICJzb3VyY2UiID0gYygwKSwNCiAgICAidGFyZ2V0IiA9IChtYXRjaCgiT3RoZXIiLCBub2RlX25hbWVzKSAtMSksDQogICAgInZhbHVlIiA9IGMob3RoZXJfZW1pc3Npb25zKQ0KICApDQogIA0KICBzdWJfc2Fua2V5X3RpYmJsZSA8LSBmaWx0ZXJlZF90aWJibGUgJT4lIA0KICAgIHNlbGVjdCgtY2F0ZWdvcnlfaWQsIC1zdWJjYXRlZ29yeV9pZCwgLXllYXIpICU+JSANCiAgICBtdXRhdGUoY2F0ZWdvcnlfbmFtZSA9IG1hdGNoKGNhdGVnb3J5X25hbWUsIG5vZGVfbmFtZXMpIC0xLA0KICAgICAgICAgICBzdWJjYXRlZ29yeV9uYW1lID0gbWF0Y2goc3ViY2F0ZWdvcnlfbmFtZSwgbm9kZV9uYW1lcykgLTEpDQogIA0KICBuYW1lcyhzdWJfc2Fua2V5X3RpYmJsZSkgPSBjKCJzb3VyY2UiLCAidGFyZ2V0IiwgInZhbHVlIikNCiAgDQogIHNhbmtleV90aWJibGUgPC0gdG90YWxfc2Fua2V5X3RpYmJsZSAlPiUgDQogICAgYmluZF9yb3dzKHN1Yl9zYW5rZXlfdGliYmxlKSAlPiUgDQogICAgYmluZF9yb3dzKHRvdGFsX290aGVyX3NhbmtleV90aWJibGUpDQogIA0KICBsaW5rc19tYXRyaXggPC0gZGF0YS5mcmFtZShhcy5tYXRyaXgoc2Fua2V5X3RpYmJsZSwgYnlyb3cgPSBUUlVFLCBuY29scyA9IDMpKQ0KICANCiAgIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIGNvbm5lY3Rpb246DQogIGxpbmtzIDwtIGxpbmtzX21hdHJpeCAlPiUgDQogICAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKA0KICAgICAgc291cmNlID09IDAgfiBwYXN0ZSgidHlwZV8iLCB0YXJnZXQsIHNlcCA9ICIiKSwNCiAgICAgIHNvdXJjZSE9MCB+IHBhc3RlKCJ0eXBlXyIsIHNvdXJjZSwgc2VwID0gIiIpDQogICAgKSkNCiAgDQogIG5vZGVzIDwtIG5vZGVfbmFtZXNfZGYNCiAgIyBBZGQgYSAnZ3JvdXAnIGNvbHVtbiB0byBlYWNoIG5vZGUuDQogICMgQWxsIG9mIHRoZW0gaW4gdGhlIHNhbWUgZ3JvdXAgdG8gbWFrZSB0aGVtIHRoZSBzYW1lIGNvbG91cg0KICBub2RlcyRncm91cCA8LSBhcy5mYWN0b3IoYygibXlfdW5pcXVlX2dyb3VwIikpDQogIA0KICBlbWlzc2lvbnMgPC0gbGlzdCgpDQogIA0KICBlbWlzc2lvbnMkbm9kZXMgPC0gbm9kZXMNCiAgZW1pc3Npb25zJGxpbmtzIDwtIGxpbmtzDQogIA0KICByZXR1cm4oZW1pc3Npb25zKQ0KfQ0KYGBgDQoNCg0KYGBge3J9DQptYWtlX3NhbmtleV9kZnMoZW1pc3Npb25zX3NhbmtleSwgdXNlclllYXIgPSAyMDA1LCB1c2VyR2FzID0gIkNINCIsIHVzZXJSZXNvbHV0aW9uID0gNTApDQpgYGANCmBgYHtyfQ0KDQpgYGANCg0K